#include <avr/io.h>
#include <avr/iom644.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <string.h>

const char		*byte_to_binary(int x);
void			USART_Init(unsigned int baudrate);
void			USART_Transmit(unsigned char data);
unsigned char	USART_Not_Block_Receive(void);
void			USART_Send_String(char *buffer);
void			EEPROM_write(unsigned int uiAddress, unsigned char ucData);
unsigned char	EEPROM_read(unsigned int uiAddress);

int baudrate = 0x00;

int
main(void) {

	unsigned char aux;
	int rate;

	DDRA = 0x00;
	DDRB = 0xFF;

	rate = EEPROM_read(baudrate);
	if (rate == 25 || rate == 6 || rate == 12) {
		USART_Init(rate);
	}
	else {
		USART_Init(25);
		EEPROM_write(baudrate, 25);
	}

	sei();

	while(1) {

		aux = PINA;

		if (aux != 0xFF) {
			if (aux == 0xDF) {
				EEPROM_write(baudrate, 25);
				USART_Init(25);
				PORTB = aux;
			}
			else if (aux == 0xBF) {
				EEPROM_write(baudrate, 12);
				USART_Init(12);
				PORTB = aux;
			}
			else if (aux == 0x7F) {
				EEPROM_write(baudrate, 6);
				USART_Init(6);
				PORTB = aux;
			}
		}
		_delay_ms(100);

	}
}

const char *byte_to_binary(int x) {
    static char b[9];
    b[0] = '\0';
    int z;
    for (z = 256; z > 0; z >>= 1)
    {
        strcat(b, ((x & z) == z) ? "1" : "0");
    }
    return b;
}

void USART_Init(unsigned int baudrate) {

	/* Se configura la veloridad de transferencia. */
	/* Ver tabla de valores. */

	UBRR0H = (unsigned char)(baudrate>>8);
	UBRR0L = (unsigned char)baudrate;

	/* Se habilita la transmision y la recepcion. */

	UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);

	/* Formato: 8data, 2stop bit. */

	UCSR0C = (1<<USBS0)|(3<<UCSZ00);

	/* Se habilitan las interrupciones. */

	sei();
}

void USART_Transmit(unsigned char data) {

	/* Se espera a que el buffer este vacio. */

	while (!( UCSR0A & (1<<UDRE0))) {
		;
	}

	/* Se pone el caracter en buffer. */

	UDR0 = data;
}

unsigned char USART_Not_Block_Receive(void) {

	/* Se lee el dato que hay en el buffer. Si no hay nada retorna 0. */

	if (UCSR0A & (1<<RXC0)) {
		return UDR0;
	}

	return 0;
}

void USART_Send_String(char *buffer) {

	unsigned char aux = 0;

	/* Se mandan todos los caracteres que se reciben. */

	do
	{
		/* Se manda cada caracter. */
		aux = *buffer;
		buffer ++;
		USART_Transmit(aux);
	}
	while (aux != 0);
}

void EEPROM_write(unsigned int uiAddress, unsigned char ucData) {

	/* Wait for completion of previous write */

	while(EECR & (1<<EEPE)) {
		;
	}

	/* Set up address and Data Registers */

	EEAR = uiAddress;
	EEDR = ucData;

	/* Write logical one to EEMPE */

	EECR |= (1<<EEMPE);

	/* Start EEPROM write by setting EEPE */

	EECR |= (1<<EEPE);
}

unsigned char EEPROM_read(unsigned int uiAddress) {

	/* Wait for completion of previous write */

	while(EECR & (1<<EEPE)) {
		;
	}

	/* Set up address register */

	EEAR = uiAddress;

	/* Start EEPROM read by writing EERE */

	EECR |= (1<<EERE);

	/* Return data from Data Register */

	return EEDR;
}

ISR(USART0_RX_vect) {

	unsigned char aux;
	char string[60] = "";

	aux = USART_Not_Block_Receive();

	if (aux != 0) {
		sprintf (string, "ASCII - Valor: %x - Simbolo: %c - Bits: %s\n\r", aux, aux, byte_to_binary(aux));
		USART_Send_String(string);
	}
}
